#region Using directives
using System;
using Microsoft.DirectX;
using SharpWind.Math;
#endregion

namespace SharpWind.Scene
{
	public abstract class Camera
	{
		#region Fields

		protected Matrix view = Matrix.Identity;
		
		protected Matrix projection = Matrix.Identity;
		
		protected Vector3 right = new Vector3( 1, 0, 0 );
		
		protected Vector3 up = new Vector3( 0, 1, 0 );
		
		protected Vector3 look = new Vector3( -0.5f, -0.5f, 0.5f );
		
		protected Vector3 position = Vector3.Empty;
		
		protected Vector3 lookAt = Vector3.Empty;

		protected float fov;
		
		protected float aspect;
		
		protected float nearPlane;
		
		protected float farPlane;

		protected BoundingFrustrum boundingFrustrum = new BoundingFrustrum();

		protected string name;

		protected bool isActive;

		#endregion

		#region Methods

		public void Activate()
		{
			if( !isActive )
			{
				Engine.Instance.Scene.ActiveCamera = this;
			}
		}

		internal virtual void Update()
		{
			this.boundingFrustrum.Rebuild( this );
		}

		protected virtual void CreateProjectionMatrix( float fov, float aspect, float near, float far )
		{
			this.fov		= fov;
			this.aspect		= aspect;
			this.nearPlane	= near;
			this.farPlane	= far;
			this.projection = Matrix.PerspectiveFovLH( this.fov, this.aspect, this.nearPlane, this.farPlane );
		}

		#endregion

		#region Properties

		public Matrix ViewMatrix
		{
			get
			{
				return this.view;
			}
		}

		public Matrix ProjectionMatrix
		{
			get
			{
				return this.projection;
			}
		}

		public Vector3 Position
		{
			get
			{
				return this.position;
			}
			set
			{
				this.position = value;
			}
		}

		public Vector3 LookAt
		{
			get
			{
				return this.lookAt;
			}
			set
			{
				this.lookAt = value;
				this.look	= Vector3.Normalize( this.lookAt - this.position );
			}
		}

		public float FieldOfView
		{
			get
			{
				return this.fov;
			}
			set
			{
				CreateProjectionMatrix( value, this.aspect, this.nearPlane, this.farPlane );
			}
		}

		public float AspectRatio
		{
			get
			{
				return this.aspect;
			}
			set
			{
				CreateProjectionMatrix( this.fov, value, this.nearPlane, this.farPlane );
			}
		}

		public float NearPlane
		{
			get
			{
				return this.nearPlane;
			}
			set
			{
				CreateProjectionMatrix( this.fov, this.aspect, value, this.farPlane );
			}
		}

		public float FarPlane
		{
			get
			{
				return this.farPlane;
			}
			set
			{
				CreateProjectionMatrix( this.fov, this.aspect, this.nearPlane, value );
			}
		}

		public BoundingFrustrum BoundingFrustrum
		{
			get
			{
				return this.boundingFrustrum;
			}
		}

		public string Name 
		{
			get
			{
				return this.name;
			}
			internal set
			{
				this.name = value;
			}
		}

		public bool IsActive
		{
			get
			{
				return this.isActive;
			}
			set
			{
				this.isActive = value;
			}
		}

		#endregion
	}
}
